{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.\n",
        "# SPDX-License-Identifier: Apache-2.0\n",
        "#\n",
        "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# http://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2f630f7c",
      "metadata": {},
      "source": [
        "# Create a Headless IsaacSim\n",
        "\n",
        "You should only have to do this part once; it will load kit, or at least the headless IsaacSim version of kit, by calling\n",
        "simulation_app = SimulationApp(CONFIG).This will take some time, so give it a minute and wait for it to say \"Hi\".\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e41f96bf",
      "metadata": {},
      "source": []
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "09ebaf0b",
      "metadata": {},
      "outputs": [],
      "source": [
        "from isaacsim import SimulationApp\n",
        "\n",
        "# Set the path below to your desired nucleus server\n",
        "simulation_app = SimulationApp()\n",
        "print(\"Hi\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dfb64239",
      "metadata": {},
      "source": [
        "\n",
        "## Create a simulation context and move camera\n",
        "\n",
        "Here we create a `SimulationContext` object which provides a high level interface to interact with the simulation\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "dd5b9ad6",
      "metadata": {},
      "outputs": [],
      "source": [
        "from isaacsim.core.api import World\n",
        "from isaacsim.core.utils.prims import create_prim\n",
        "from isaacsim.core.utils.viewports import set_camera_view\n",
        "from isaacsim.storage.native import get_assets_root_path\n",
        "from isaacsim.core.api.materials.omni_glass import OmniGlass\n",
        "from isaacsim.core.prims import SingleXFormPrim\n",
        "from isaacsim.core.utils.extensions import get_extension_path_from_name\n",
        "from isaacsim.core.utils.semantics import add_labels\n",
        "\n",
        "import omni\n",
        "import carb\n",
        "import numpy as np\n",
        "\n",
        "simulation_world = World(stage_units_in_meters=1.0)\n",
        "set_camera_view(eye=np.array([-0.9025, 2.1035, 1.0222]), target=np.array([0.6039, 0.30, 0.0950]))\n",
        "\n",
        "# Step our simulation to ensure everything initialized\n",
        "simulation_world.step()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "1c02f8f3",
      "metadata": {},
      "source": [
        "## Creating the scene\n",
        "\n",
        "Re-run the cell below to randomize the scene from scratch. The goal here is to make iterating on scene setup easy and not require restarts of the omniverse application.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "fd004b53",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Delete everything in the stage\n",
        "simulation_world.clear()\n",
        "# SCENE SETUP\n",
        "\n",
        "# Add a distant light\n",
        "create_prim(\"/DistantLight\", \"DistantLight\", attributes={\"inputs:intensity\": 500})\n",
        "\n",
        "# Add a ground collision plane\n",
        "simulation_world.scene.add_ground_plane(size=1000, z_position=-0.5, color=np.array([1, 1, 1]))\n",
        "\n",
        "# Load a URDF\n",
        "status, import_config = omni.kit.commands.execute(\"URDFCreateImportConfig\")\n",
        "import_config.merge_fixed_joints = False\n",
        "import_config.convex_decomp = False\n",
        "import_config.import_inertia_tensor = True\n",
        "import_config.fix_base = False\n",
        "import_config.distance_scale = 1.0\n",
        "import_config.create_physics_scene = False  # we already have a physics scene from simulation_world\n",
        "\n",
        "# Get path to extension data:\n",
        "extension_path = get_extension_path_from_name(\"isaacsim.asset.importer.urdf\")\n",
        "# Import URDF, stage_path contains the path the path to the usd prim in the stage.\n",
        "status, stage_path = omni.kit.commands.execute(\n",
        "    \"URDFParseAndImportFile\",\n",
        "    urdf_path=extension_path + \"/data/urdf/robots/carter/urdf/carter.urdf\",\n",
        "    import_config=import_config,\n",
        ")\n",
        "stage = simulation_world.stage\n",
        "add_labels(stage.GetPrimAtPath(stage_path), labels=[\"Robot\"], instance_name=\"class\")\n",
        "\n",
        "# Load a mesh\n",
        "assets_root_path = get_assets_root_path()\n",
        "if assets_root_path is None:\n",
        "    carb.log_error(\"Could not find Isaac Sim assets folder\")\n",
        "usd_path = assets_root_path + \"/Isaac/Props/YCB/Axis_Aligned/006_mustard_bottle.usd\"\n",
        "\n",
        "prim = create_prim(prim_path=\"/Mesh\", usd_path=usd_path, scale=np.array([10.0, 10.0, 10.0]), semantic_label=\"mustard\")\n",
        "xform_prim = SingleXFormPrim(prim.GetPath().pathString)\n",
        "\n",
        "\n",
        "# Apply a glass material to mesh\n",
        "material = OmniGlass(\n",
        "    \"/Looks/GlassMaterial\", name=\"glass_material\", ior=1.25, depth=0.001, thin_walled=False, color=np.random.rand(3)\n",
        ")\n",
        "xform_prim.apply_visual_material(material)\n",
        "\n",
        "# Set mesh transform\n",
        "xform_prim.set_world_pose(position=np.array([1.00, 0, 0]))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "327aed4d",
      "metadata": {},
      "source": [
        "## Viewing the scene in the notebook\n",
        "\n",
        "This next example does not change the scene (but it could if you used commands like the ones above), but it does visualize the synthetic data by accesing the underlying annotator data. Specifically, it shows a color, depth, and segmentation view of the scene, and then displays them within the notebook.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d3ba55ad",
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "from omni.syntheticdata import visualize\n",
        "from omni.kit.viewport.utility import get_active_viewport\n",
        "import omni.replicator.core as rep\n",
        "\n",
        "viewport_api = get_active_viewport()\n",
        "active_cam = viewport_api.get_active_camera()\n",
        "resolution = viewport_api.get_texture_resolution()\n",
        "render_product = rep.create.render_product(active_cam, resolution)\n",
        "\n",
        "rgb = rep.AnnotatorRegistry.get_annotator(\"rgb\")\n",
        "rgb.attach([render_product])\n",
        "depth = rep.AnnotatorRegistry.get_annotator(\"distance_to_image_plane\")\n",
        "depth.attach([render_product])\n",
        "semantic_segmentation = rep.AnnotatorRegistry.get_annotator(\"semantic_segmentation\")\n",
        "semantic_segmentation.attach([render_product])\n",
        "\n",
        "# Run the application for multiple frames to ensure the synthetic data pipeline is initialized\n",
        "timeline = omni.timeline.get_timeline_interface()\n",
        "timeline.play()\n",
        "for _ in range(10):\n",
        "    simulation_app.update()\n",
        "timeline.pause()\n",
        "\n",
        "# Get groundtruth\n",
        "rgb_data = rgb.get_data()\n",
        "depth_data = depth.get_data()\n",
        "semantic_segmentation_data = semantic_segmentation.get_data()\n",
        "\n",
        "# GROUNDTRUTH VISUALIZATION\n",
        "# Setup a figure\n",
        "_, axes = plt.subplots(1, 3, figsize=(20, 7))\n",
        "axes = axes.flat\n",
        "for ax in axes:\n",
        "    ax.axis(\"off\")\n",
        "\n",
        "# RGB\n",
        "axes[0].set_title(\"RGB\")\n",
        "axes[0].imshow(rgb_data)\n",
        "\n",
        "# DEPTH\n",
        "axes[1].set_title(\"Depth\")\n",
        "depth_data_clipped = np.clip(depth_data, 0, 255)\n",
        "axes[1].imshow(visualize.colorize_distance(depth_data.squeeze()))\n",
        "\n",
        "# SEMANTIC SEGMENTATION\n",
        "axes[2].set_title(\"Semantic Segmentation\")\n",
        "# Draw the segmentation mask on top of the color image with a transparency\n",
        "axes[2].imshow(rgb_data)\n",
        "semantic_segmentation_rgb = visualize.colorize_segmentation(semantic_segmentation_data[\"data\"])\n",
        "axes[2].imshow(semantic_segmentation_rgb, alpha=0.7)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c1e98ae2",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Cleanup application\n",
        "simulation_app.close()\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Isaac Sim Python 3",
      "language": "python",
      "name": "isaac_sim_python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.15"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
